﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChatContrats;
using System.ServiceModel;
using System.Threading;
using System.Collections;

namespace ChatServices
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, //1 objet crée par client
        ConcurrencyMode = ConcurrencyMode.Single) //associé à Session: 1 seul appel par client à la fois, mais plusieurs client simultanément
        //ConcurrencyMode = ConcurrencyMode.Reentrant)
    ]
    public class ChatWCF : IChatWCF
    {
        internal static event ChatMessageEventHandler ChatMessageEvent;
        internal delegate void ChatMessageEventHandler(object sender, ChatMessageEventArgs e);

        internal static event ConnexionEventHandler ConnexionEvent;
        internal delegate void ConnexionEventHandler(object sender, ConnexionEventArgs e);

        internal static event DeconnexionEventHandler DeconnexionEvent;
        internal delegate void DeconnexionEventHandler(object sender, DeconnexionEventArgs e);

        //pour rappeler le client
        private IChatWCFRappel callback = null;

        //pseudo de l'utilisateur
        private String pseudoUtilisateur = null;

        //liste des utilisateurs connectés
       // internal static List<Hashtable> listeUtilisateurs = new List<Hashtable>();
        internal static Hashtable listeUtilisateurs = new Hashtable();
        public void DemarrerSession(String pseudo)
        {
            Console.WriteLine("Tentative de connexion de l'utilisateur {0}", pseudo);

            callback = OperationContext.Current.GetCallbackChannel<IChatWCFRappel>();

            pseudoUtilisateur = pseudo;

            lock (listeUtilisateurs)
            {
                if (!listeUtilisateurs.Contains(pseudo))
                {
                    listeUtilisateurs.Add(pseudo, callback);

                    //on s'abonne à la réception de nouveaux messages
                    ChatMessageEvent += ChatMessageHandler;

                    //on s'abonne à la connexion de nouveaux utilisateurs
                    ConnexionEvent += ConnexionHandler;

                    //on s'abonne à la déconnexion d'utilisateurs
                    DeconnexionEvent += DeconnexionHandler;

                    //on informe les utilisateurs de la connexion d'un nouveau venu
                    ConnexionEventArgs cea = new ConnexionEventArgs();
                    cea.Utilisateur = this.pseudoUtilisateur;
                    ConnexionEvent(this, cea);

                    OperationContext.Current.Channel.Closing += new EventHandler(Channel_Closing);

                    Console.WriteLine("Connexion de l'utilisateur {0}", pseudoUtilisateur);
                   

                }
                else
                {
                    callback.UtilisateurExistant(pseudoUtilisateur);
                }

            }
            
        }

        public void EnvoyerMessagePrive(String emmeteur, String destinataire, String message)
        {
            if(listeUtilisateurs.Contains(destinataire))
            {
            IChatWCFRappel callback = (IChatWCFRappel)listeUtilisateurs[destinataire];
            callback.newPrivateMessage(emmeteur, emmeteur + " dit : "+ message);
            Console.WriteLine(emmeteur + "--> " + destinataire + " : " + message);
            }
        }


        public void getListeUtilisateur()
        {
            this.callback.giveListeUtilisateur(listeUtilisateurs);
        }

        //le client ferme le canal
        private void Channel_Closing(object sender, EventArgs e)
        {
            Console.WriteLine("Fermeture du channel par {0}", pseudoUtilisateur);
            //si on n'est pas passé par FermerSession avant
            lock (listeUtilisateurs)
            {
                
                if (listeUtilisateurs.Contains(this.pseudoUtilisateur))
                    FermerSession();
            }
        }

        public void FermerSession()
        {
            lock (listeUtilisateurs)
            {
                //on désabonne le client
                ChatMessageEvent -= ChatMessageHandler;
                ConnexionEvent -= ConnexionHandler;
                DeconnexionEvent -= DeconnexionHandler;
           
                listeUtilisateurs.Remove(this.pseudoUtilisateur);
                
            }

            //on informe les utilisateurs de la déconnexion 
            DeconnexionEventArgs dea = new DeconnexionEventArgs();
            dea.Utilisateur = this.pseudoUtilisateur;

            if (DeconnexionEvent != null)
                DeconnexionEvent(this, dea);

            Console.WriteLine("Déconnexion de l'utilisateur {0}", this.pseudoUtilisateur);
        }

        public void EnvoyerMessage(string message)
        {
            //on informe les utilisateurs d'un nouveau message
            ChatMessageEventArgs mea = new ChatMessageEventArgs();
            mea.Message = message; //le message
            mea.Utilisateur = this.pseudoUtilisateur; //l'expéditeur
            ChatMessageEvent(this, mea);
        }


        //méthode appelée quand l'évènement ChatMessageEvent est déclanché
        private void ChatMessageHandler(object sender, ChatMessageEventArgs e)
        {
            callback.ReceptionMessage(e.Utilisateur, e.Message);
            Console.WriteLine("{0} / {1} : {2}", this.pseudoUtilisateur, e.Utilisateur, e.Message);
        }

        //méthode appelée quand l'évènement DeconnexionEvent est déclanché
        private void DeconnexionHandler(object sender, DeconnexionEventArgs e)
        {
            callback.DeconnexionUtilisateur(e.Utilisateur);
            callback.deconnexionUtilisateurListe(e.Utilisateur);
        }

        //méthode appelée quand l'évènement ConnexionEvent est déclanché
        private void ConnexionHandler(object sender, ConnexionEventArgs e)
        {
            
            callback.ConnexionUtilisateur(e.Utilisateur);
            callback.nouvelUtilisateurListe(e.Utilisateur);
        }
    }


    internal class ChatMessageEventArgs : EventArgs
    {
        public String Message { get; set; }
        public String Utilisateur { get; set; } //expéditeur du message
    }

    internal class DeconnexionEventArgs : EventArgs
    {
        public String Utilisateur { get; set; }
    }

    internal class ConnexionEventArgs : EventArgs
    {
        public String Utilisateur { get; set; }
    }
}
